﻿using System;
using System.Linq;
using Raven.Client;

namespace Actya.Core.Security
{
	public class DefaultMembershipService : IMembershipService
	{
		private readonly IDocumentSession _session;

		public DefaultMembershipService(IDocumentSession session)
		{
			_session = session;
		}

		public User AuthenticateUser(string username, string password)
		{
			var user = _session.Query<User>().SingleOrDefault(u => u.Username == username);
			if (user == null)
			{
				return new User { IsAuthenticated = false };
			}
			user.IsAuthenticated = user.PasswordHash == PasswordUtil.HashPassword(password, user.PasswordSalt);
			if (user.IsAuthenticated)
			{
				user.DateLastLogin = DateTime.Now;
				_session.SaveChanges();
			}
			return user;
		}

		public User GetUserByUsername(string username, bool isUserOnline)
		{
			var user = _session.Query<User>().SingleOrDefault(u => u.Username == username);
			if (user != null && isUserOnline)
			{
				user.DateLastLogin = DateTime.Now;
				_session.SaveChanges();
			}
			return user;
		}

		public void CreateRole(string roleName)
		{
			var existingRole = _session.Load<Role>(roleName);
			if (existingRole == null)
			{
				var role = new Role { Id = roleName };
				_session.Store(role);
				_session.SaveChanges();				
			}
		}

		public User CreateUser(string username, string password, string defaultRole)
		{
			var existingUser = AuthenticateUser(username, password);
			if (!existingUser.IsAuthenticated && existingUser.Username != null) // User exists but wrong password.
			{
				throw new Exception("The user already exists, but the wrong password was supplied.");
			}
			if (existingUser.IsAuthenticated) // Existing user: just return the that one and don't create a new one.
			{
				if (! existingUser.IsInRole(defaultRole))
				{
					existingUser.Roles.Add(defaultRole);
				}
				return existingUser;
			}
			var user = new User();
			user.Username = username;
			user.PasswordSalt = PasswordUtil.CreateRandomSalt();
			user.PasswordHash = PasswordUtil.HashPassword(password, user.PasswordSalt);
			user.Roles.Add(defaultRole);
			user.DateCreated = DateTime.Now;
			_session.Store(user);
			_session.SaveChanges();

			return user;
		}
	}
}
